#include <Windows.h>
#include "OwnerDrawButton.h"

const int g_nCaptionLen = 50;

COwnerDrawButton::COwnerDrawButton(void) : m_hWnd(NULL), m_hFourStateBitmap(NULL),
                                           m_fTrackMouse(FALSE)
{
}

COwnerDrawButton::~COwnerDrawButton(void)
{
    if (m_hFourStateBitmap)
    {
        DeleteObject(m_hFourStateBitmap);
    }
    if (m_hFont)
    {
        DeleteObject(m_hFont);
    }
}

BOOL COwnerDrawButton::Create(LPCTSTR lpszCaption, const RECT &rect, HWND hParentWnd,
                              UINT nID, LPCTSTR lpszImage)
{
    if (m_hWnd)
        return FALSE;


    m_hWnd = CreateWindow(TEXT("BUTTON"), lpszCaption,
                          WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_OWNERDRAW,
                          rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
                          hParentWnd, (HMENU)nID, NULL, NULL);

    if (NULL == m_hWnd)
    {
        MessageBox(NULL, TEXT("m_hWnd"), TEXT("m_hWnd"), MB_OK);
        goto CREATE_FAIL;
    }

    m_OldProc = (WNDPROC)SetWindowLongPtr(m_hWnd, GWLP_WNDPROC, (LONG_PTR)ButtonProc);
    SetWindowLong(m_hWnd, GWLP_USERDATA, (LONG_PTR)this);

    m_hFont = CreateFont(12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, 0, ANSI_CHARSET,
                         OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, TEXT("Arial"));

    return TRUE;

CREATE_FAIL:
    if (m_hFourStateBitmap)
    {
        DeleteObject(m_hFourStateBitmap);
    }
    return FALSE;
}

LRESULT CALLBACK COwnerDrawButton::ButtonProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    PAINTSTRUCT ps;
    HDC hdc;
    COwnerDrawButton *_this = (COwnerDrawButton *)GetWindowLongPtr(hWnd, GWLP_USERDATA);
    _this->m_hWnd = hWnd;

    switch (message)
    {
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
        // TODO: Add any drawing code here...
        _this->Draw(hdc);
        EndPaint(hWnd, &ps);
        break;
    case WM_ERASEBKGND:
        return TRUE;
    case WM_DRAWITEM:
    {
        DRAWITEMSTRUCT *pDrawItemSturct = (DRAWITEMSTRUCT *)lParam;

        if (pDrawItemSturct->itemState & ODS_FOCUS)
        {
            RECT rtFocus = pDrawItemSturct->rcItem;
            rtFocus.left += 3;
            rtFocus.top += 3;
            rtFocus.right -= 3;
            rtFocus.bottom -= 3;
            _this->DrawFocusRect(pDrawItemSturct->hDC, rtFocus);
        }
        //_this->Draw(pDrawItemSturct->hDC);
    }
    break;
    case WM_LBUTTONDOWN:
    {
        _this->OnLbuttonDown(wParam, lParam);
    }
    break;
    case WM_LBUTTONUP:
    {
        _this->OnLbuttonUp(wParam, lParam);
    }
    break;
    case WM_LBUTTONDBLCLK:
    {
        _this->OnLbuttonDBClick(wParam, lParam);
    }
    break;
    case WM_MOUSEMOVE:
    {
        _this->OnMouseMove(wParam, lParam);
    }
    break;
    case WM_MOUSELEAVE:
    {
        _this->OnMouseLeave(wParam, lParam);
    }
    break;
    default:
        return CallWindowProc(_this->m_OldProc, hWnd, message, wParam, lParam);
    }
    return 0;
}
void COwnerDrawButton::OnLbuttonDown(WPARAM wParam, LPARAM lParam)
{
    SetCapture(m_hWnd);
    m_nButtonState = STATE_DOWN;
    InvalidataCtrl();
}
void COwnerDrawButton::OnLbuttonUp(WPARAM wParam, LPARAM lParam)
{
    if (m_nButtonState == STATE_DOWN)
    {
        ReleaseCapture();
        POINT pt = {};
        GetCursorPos(&pt);
        RECT rcWnd = {};
        GetWindowRect(m_hWnd, &rcWnd);
        if (PtInRect(&rcWnd, pt))
        {
            m_fTrackMouse = TRUE;
            m_nButtonState = STATE_FOCUS;
            SendMessage(GetParent(m_hWnd), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(m_hWnd), BN_CLICKED), (LPARAM)m_hWnd);
        }
        else
        {
            m_fTrackMouse = FALSE;
            m_nButtonState = STATE_UP;
        }
        InvalidataCtrl();
    }
}

void COwnerDrawButton::OnLbuttonDBClick(WPARAM wParam, LPARAM lParam)
{
    SendMessage(m_hWnd, WM_LBUTTONDOWN, NULL, NULL);
}

void COwnerDrawButton::OnMouseMove(WPARAM wParam, LPARAM lParam)
{
    if (!m_fTrackMouse)
    {
        TRACKMOUSEEVENT MouseEvent = {sizeof(TRACKMOUSEEVENT)};
        MouseEvent.dwFlags = TME_LEAVE;
        MouseEvent.hwndTrack = m_hWnd;
        MouseEvent.dwHoverTime = 1000;
        TrackMouseEvent(&MouseEvent);

        m_fTrackMouse = TRUE;
        m_nButtonState = STATE_FOCUS;
        InvalidataCtrl();
    }
}

void COwnerDrawButton::OnMouseLeave(WPARAM wParam, LPARAM lParam)
{
    m_fTrackMouse = FALSE;
    m_nButtonState = STATE_UP;
    InvalidataCtrl();
}

void COwnerDrawButton::Draw(HDC hDC)
{
    HDC hMemDC = CreateCompatibleDC(hDC);
    HBITMAP hOldBmp = NULL;
    BITMAP bmpInfo = {};

    hOldBmp = (HBITMAP)SelectObject(hMemDC, m_hFourStateBitmap);
    GetObject(m_hFourStateBitmap, sizeof(bmpInfo), &bmpInfo);

    RECT rcWnd = {};
    GetClientRect(m_hWnd, &rcWnd);
    int nWidth = rcWnd.right - rcWnd.left;
    int nHeight = rcWnd.bottom - rcWnd.top;
    int nBmpWidth = bmpInfo.bmWidth / 4;
    int nBmpHeight = bmpInfo.bmHeight;
    //绘制背景图
    SetStretchBltMode(hDC, HALFTONE);
    StretchBlt(hDC, 0, 0, nWidth, nHeight, hMemDC, nBmpWidth * m_nButtonState,
               0, nBmpWidth, nBmpHeight, SRCCOPY);

    if (m_nButtonState == STATE_DOWN)
    {
        rcWnd.top += 2;
    }

    //绘制文本
    TCHAR szCaption[g_nCaptionLen] = {};
    GetWindowText(m_hWnd, szCaption, g_nCaptionLen - 1);
    if (lstrlen(szCaption) > 0)
    {
        SetBkMode(hDC, TRANSPARENT);
        TCHAR *pReturnPos = NULL;
        HFONT hOldFont = (HFONT)SelectObject(hDC, m_hFont);
        if (pReturnPos = (TCHAR *)strstr((const char *)szCaption, "\\r\\n"))
        {
            // pReturnPos[0] = '\r';
            // pReturnPos[1] = '\n';
            // strcpy(&pReturnPos[2], &pReturnPos[4]);
            TCHAR *pszSecondLine = pReturnPos + 4;
            rcWnd.bottom = (rcWnd.bottom + rcWnd.top) / 2;
            rcWnd.top += 1;
            DrawText(hDC, szCaption, pReturnPos - szCaption, &rcWnd, DT_CENTER);
            rcWnd.top -= 1;
            rcWnd.bottom = rcWnd.bottom * 2 - rcWnd.top;
            rcWnd.top = (rcWnd.bottom + rcWnd.top) / 2;
            rcWnd.top -= 1;
            DrawText(hDC, pszSecondLine, lstrlen(pszSecondLine), &rcWnd, DT_CENTER);
        }
        else
        {
            DrawText(hDC, szCaption, lstrlen(szCaption), &rcWnd, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
        }
        SelectObject(hDC, hOldFont);
    }

    SelectObject(hMemDC, hOldBmp);
    DeleteDC(hMemDC);
}

void COwnerDrawButton::DrawFocusRect(HDC hDC, RECT &rcWnd)
{
    HPEN hOldPen = NULL;
    HPEN hDrawPen = CreatePen(PS_DOT, 2, RGB(0, 0, 0));

    HBRUSH hBrush = (HBRUSH)GetStockObject(NULL_BRUSH);
    HBRUSH hOldBrush = (HBRUSH)SelectObject(hDC, hBrush);
    hOldPen = (HPEN)SelectObject(hDC, hDrawPen);
    Rectangle(hDC, rcWnd.left, rcWnd.top, rcWnd.right, rcWnd.bottom);

    SelectObject(hDC, hOldBrush);
    SelectObject(hDC, hOldPen);
    DeleteObject(hDrawPen);
}

bool COwnerDrawButton::InvalidataCtrl()
{
    // RECT rcWnd = {};
    // GetClientRect(m_hWnd, &rcWnd);
    // InvalidateRect(m_hWnd, &rcWnd, bErase);
    HDC hDC = GetDC(m_hWnd);
    Draw(hDC);
    ReleaseDC(m_hWnd, hDC);
    return true;
}

void COwnerDrawButton::EnableButton(bool fEnable)
{
    if (fEnable)
    {
        m_nButtonState = STATE_UP;
    }
    else
    {
        m_nButtonState = STATE_DISABLE;
    }
    EnableWindow(m_hWnd, fEnable);
    InvalidataCtrl();
}